package com.cyt.web.controller.thrid;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.cyt.base.model.dto.ReturnResult;
import com.cyt.base.util.*;
import com.cyt.reward.model.po.RewardRecord;
import com.cyt.reward.model.po.RewardStaff;
import com.cyt.reward.service.RewardRecordService;
import com.cyt.reward.service.RewardStaffService;
import com.cyt.reward.util.RewardDictCode;
import com.cyt.thrid.wechat.model.base.*;
import com.cyt.thrid.wechat.url.WxUrlUtil;
import com.cyt.web.controller.base.PhoneController;
import com.cyt.web.thrid.wechat.WxApiClient;
import com.cyt.web.thrid.wechat.WxMemoryCacheClient;
import com.cyt.wx.model.po.WxAccount;
import com.cyt.wx.model.po.WxApply;
import com.cyt.wx.model.po.WxApplyUse;
import com.cyt.wx.model.po.WxMember;
import com.cyt.wx.model.vo.WxMemberVo;
import com.cyt.wx.service.WxApplyService;
import com.cyt.wx.service.WxApplyUseService;
import com.cyt.wx.service.WxMemberService;
import com.github.pagehelper.StringUtil;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;

/**
 * 微信端controller层
 *
 * @author shengQiang yu
 * @date 2019-4-26 11:34:01
 */
@Controller
@RequestMapping("/weChat")
@Slf4j
public class WeChatController extends PhoneController {
    @Autowired
    private WxApplyUseService wxApplyUseService;
    @Autowired
    private WxApplyService wxApplyService;
    @Autowired
    private RewardRecordService rewardRecordService;
    @Autowired
    private RewardStaffService rewardStaffService;
    @Autowired
    private WxMemberService wxMemberService;

    /**
     * oauth2.0跳转入库
     * */
    @RequestMapping("/oauth")
    public ModelAndView oauth(HttpServletResponse response, HttpServletRequest request) throws IOException {
        String oauthType = request.getParameter("oauthType");
        String applyId = request.getParameter("applyId");
        String path = request.getParameter("path");
        String pathParams = request.getParameter("pathParams");
        String scope= OAuthScope.Base.toString();
        if(OAuthScope.Userinfo.toString().equals(oauthType)){
            scope= OAuthScope.Userinfo.toString();
        }
        //获取缓存中的唯一帐号
        WxApply wxApply = wxApplyService.selectByPrimaryKey(applyId);
        WxAccount wxAccount=WxMemoryCacheClient.getWxAccount(wxApply.getAccountId());
        String url = WxUrlUtil.getOAuthCodeUrl(wxAccount.getAppId(), ProProperties.getInstance().getBaseUrl()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL()+"?applyId="+applyId+"&path="+path+"&pathParams="+pathParams,scope);
        return new ModelAndView("redirect:" + url);
    }

    /**
     * 获取openid 并跳转
     * */
    @RequestMapping("/acceptOpenid")
    public ModelAndView acceptOpenid(HttpServletResponse response, HttpServletRequest request) throws IOException {
        String code = request.getParameter("code");
        // 获取到的state是模式页面组合，模式由一个字符，1表示base,2表示userinfo,其他为页面标识符
        String scope = request.getParameter("state");
        String applyId = request.getParameter("applyId");
        String path = request.getParameter("path");
        String pathParams = request.getParameter("pathParams");
        if("null".equals(applyId)){
            applyId="";
        }
        if("null".equals(path)){
            path="";
        }
        if("null".equals(pathParams)){
            pathParams="";
        }
        ModelAndView modelAndView=null;
        try {
            // 获取缓存中的唯一帐号
            WxApply wxApply = wxApplyService.selectByPrimaryKey(applyId);
            WxAccount wxAccount=WxMemoryCacheClient.getWxAccount(wxApply.getAccountId());
            OAuthAccessToken oAuthAccessToken = WxApiClient.getOAuthOpenId(wxAccount, code);
            log.info("openid is "+oAuthAccessToken.getOpenid());
            if (StringUtils.isEmpty(oAuthAccessToken.getOpenid())) {
                //跳转到oauth2.0的url
                String url = WxUrlUtil.getOAuthCodeUrl(wxAccount.getAppId(), ProProperties.getInstance().getBaseUrl()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL()+"?applyId="+applyId+"&path="+path+"&pathParams="+pathParams, OAuthScope.Base.toString());
                modelAndView =  new ModelAndView("redirect:" + url);
            }else{
                //判断当前用户是否已经保存到数据库
                WxMember member = createUser(oAuthAccessToken,scope,applyId,wxApply.getUserId());
                if (member != null) {
                    String url="";
                    if(StringUtil.isNotEmpty(path)&&!("null".equalsIgnoreCase(path))){
                        url=path+"?token="+member.getToken()+"&applyId="+applyId;
                        if(StringUtil.isNotEmpty(pathParams)&&!("null".equalsIgnoreCase(pathParams))){
                            String[] t=pathParams.split(",");
                            for (String c:t){
                                String[] k=c.split("\\*");
                                url+="&"+k[0]+"="+k[1];
                            }
                        }
                    }
                    modelAndView = acceptView(applyId,member,url);
                } else {
                    //跳转到oauth2.0的url
                    String url = WxUrlUtil.getOAuthCodeUrl(wxAccount.getAppId(), ProProperties.getInstance().getBaseUrl()+ ProProperties.getInstance().getWxOauthAcceptOpenidURL()+"?applyId="+applyId+"&path="+path+"&pathParams="+pathParams, OAuthScope.Userinfo.toString());
                    modelAndView =  new ModelAndView("redirect:" + url);
                }
                return modelAndView;
            }
        } catch (Exception e) {
            //跳转错误页面
            e.printStackTrace();
        }
        return modelAndView;
    }


    protected ModelAndView acceptView(String applyId, WxMember member, String url){
        ModelAndView modelAndView=null;
        if(StringUtil.isNotEmpty(url)) {
            //参数页面
            modelAndView = new ModelAndView("redirect:" + url);
        }else{
            WxApply wxApply = wxApplyService.selectByPrimaryKey(applyId);
            WxApplyUse wxApplyUse= wxApplyUseService.selectByPrimaryKey(wxApply.getApplyUseId());
            //默认页面
            modelAndView = new ModelAndView("redirect:"+String.format(wxApplyUse.getPhonePath(),member.getToken(),applyId));
        }
        return  modelAndView;
    }

    /**
     * 创建本地用户
     * @return
     */
    protected WxMember createUser(OAuthAccessToken oAuthAccessToken, String scope, String applyId, String userId){
        List<WxMember> wxMemberList=wxMemberService.listExample(new WxMemberVo(oAuthAccessToken.getOpenid(),applyId));
        if(wxMemberList !=null&&wxMemberList.size()>0){
            //用户存在
            return wxMemberList.get(0);
        }else{

            // 用户不存在
            if(BaseConstant.OAUTH_USERINFO.equals(scope)){
                //Oauth为获取用户信息模式
                User user= WxApiClient.getOAuthUserInfo(oAuthAccessToken);
                if(user!=null){
                    //将用户信息插入数据库
                    WxMember member=new WxMember();
                    member.setId(BaseUtil.uId());
                    member.setOpenid(user.getOpenid());
                    member.setHeadLogo(user.getHeadimgurl());
                    if(StrUtil.isNotEmpty(user.getNickname())){
                        member.setNickName(BaseUtil.encodeBase64String(user.getNickname()));
                    }
                    member.setUserId(userId);
                    member.setApplyId(applyId);
                    member.setToken(BaseUtil.uToken());
                    member.setTokenEndTime(DateUtil.getMonthOfDate(new Date(),365));
                    member.setRemoveTag(BaseConstant.REMOVE_TAG_NO);
                    member.setUpdateTime(new Date());
                    member.setCreateTime(new Date());
                    int ids=wxMemberService.insert(member);
                    if(ids>0){
                        return member;
                    }
                }
            }
            return null;
        }
    }
    /**
     * 微信支付
     * */
    @RequestMapping(value = "/createMenu")
    public @ResponseBody
    ReturnResult createMenu(String applyId){
        String s="{\"button\":[{\"type\":\"view\",\"name\":\"微网站\",\"url\":\"http://test.whcykj.net/weChat/oauth?applyId=156272172337274310848\"},{\"type\":\"view\",\"name\":\"打赏\",\"url\":\"http://test.whcykj.net/weChat/oauth?applyId=156393985536451215803\"}]}";
        JSONObject jsonObject=WxApiClient.createMenu(applyId,s);
        return new ReturnResult(jsonObject);
    }
    /**
     * 微信支付
     * */
    @RequestMapping(value = "/pay",method = RequestMethod.POST)
    public @ResponseBody
    ReturnResult pay(String openid,String recordId, String applId, HttpServletRequest request){
        RewardRecord rewardRecord=rewardRecordService.selectByPrimaryKey(recordId);
        if(StringUtil.isNotEmpty(openid) && rewardRecord.getMoney() > 0&&RewardDictCode.REWARD_PAY_STATUS_DZF.equals(rewardRecord.getPayStatus())){
            //获取订单号
            String id="E" + System.currentTimeMillis() + RandomUtil.randomNumbers(6);
            //获取时间戳
            String timeStamp= DateUtil.create_timestamp();
            //获取ip地址
            String ip= request.getRemoteAddr();
            WxApply wxApply = wxApplyService.selectByPrimaryKey(applId);
            WxAccount wxAccount=WxMemoryCacheClient.getWxAccount(wxApply.getAccountId());

            RewardStaff rewardStaff=rewardStaffService.selectByPrimaryKey(rewardRecord.getStaffId());
            String name="您向"+rewardStaff.getName()+"打赏"+rewardRecord.getMoney()+"元";
            Return_pay pay=WxApiClient.WeiXin(recordId,name,(int)(rewardRecord.getMoney()*100), openid,ProProperties.getInstance().getBaseUrl()+ProProperties.getInstance().getWxPayRequestURL(),id,ip,timeStamp,wxAccount.getAppId(),wxAccount.getPayMachId(),wxAccount.getPayKey());
            pay.setId(id);
            log.info(pay.toString());
            if(pay==null||"".equals(pay)){
                return new ReturnResult(ErrorCode.CODE_0,BaseConstant.WECHAT_PAY_FAILL);
            }else{
                return new ReturnResult(pay);
            }
        }else{
            return new ReturnResult(ErrorCode.CODE_0,BaseConstant.DATABASE_ERROR_CANSHU);
        }
    }
    /**
     * 微信支付发货通知
     * */
    @RequestMapping(value = "/pay/sendNotice")
    public void sendNotice( HttpServletRequest request,HttpServletResponse response) throws IOException {
        response.setContentType("text/xml;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        request.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        StringBuilder buff = new StringBuilder();

        buff.append("<?xml version= \"1.0\" encoding=\"utf-8\"?>");

        String postStr=null;
        try{
            postStr=this.readStreamParameter(request.getInputStream());
        }catch(Exception e){
            log.error("Error SendProductNoticeServiceImpl method get postStr:"+ e);
        }
        Return_Notice_Pay pay=new Return_Notice_Pay();
        if (null!=postStr&&!postStr.isEmpty()){
            Document document=null;
            try{
                document = DocumentHelper.parseText(postStr);
            }catch(Exception e){
                log.error("Error SendProductNoticeServiceImpl method get document:"+ e);
            }
            if(null==document){
                buff.append("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>");
                out.print(buff.toString());
                return;
            }
            Element root=document.getRootElement();
            String return_code = root.elementText("return_code");
            log.info("return_code:"+return_code);
            pay.setReturn_code(return_code);
            if("SUCCESS".equalsIgnoreCase(return_code)){
                String appid = root.elementText("appid");
                pay.setAppid(appid);
                log.info("appid:"+appid);

                String mch_id = root.elementText("mch_id");
                pay.setMch_id(mch_id);
                log.info("mch_id:"+mch_id);

                String nonce_str = root.elementText("nonce_str");
                pay.setNonce_str(nonce_str);
                log.info("nonce_str:"+nonce_str);

                String device_info = root.elementText("device_info");
                pay.setDevice_info(device_info);
                log.info("device_info:"+device_info);

                String sign = root.elementText("sign");
                pay.setSign(sign);
                log.info("sign:"+sign);

                String result_code = root.elementText("result_code");
                pay.setResult_code(result_code);
                log.info("result_code:"+result_code);

                if("SUCCESS".equalsIgnoreCase(result_code)){
                    String openid = root.elementText("openid");
                    pay.setOpenid(openid);
                    log.info("openid:"+openid);

                    String is_subscribe = root.elementText("is_subscribe");
                    pay.setIs_subscribe(is_subscribe);
                    log.info("is_subscribe:"+is_subscribe);

                    String trade_type = root.elementText("trade_type");
                    pay.setTrade_type(trade_type);
                    log.info("trade_type:"+trade_type);

                    String bank_type = root.elementText("bank_type");
                    pay.setBank_type(bank_type);
                    log.info("bank_type:"+bank_type);

                    String total_fee = root.elementText("total_fee");
                    pay.setTotal_fee(Integer.parseInt(total_fee));
                    log.info("total_fee:"+total_fee);

                    String coupon_fee = root.elementText("coupon_fee");
                    if(coupon_fee!=null&&!"".equals(coupon_fee)){
                        pay.setCoupon_fee(Integer.parseInt(coupon_fee));
                    }
                    log.info("coupon_fee:"+coupon_fee);

                    String fee_type = root.elementText("fee_type");
                    pay.setFee_type(fee_type);
                    log.info("fee_type:"+fee_type);

                    String transaction_id = root.elementText("transaction_id");
                    pay.setTransaction_id(transaction_id);
                    log.info("transaction_id:"+transaction_id);

                    String out_trade_no = root.elementText("out_trade_no");
                    pay.setOut_trade_no(out_trade_no);
                    log.info("out_trade_no:"+out_trade_no);

                    String attach = root.elementText("attach");
                    pay.setAttach(attach);
                    log.info("attach:"+attach);

                    String time_end = root.elementText("time_end");
                    pay.setTime_end(time_end);
                    log.info("attach:"+attach);

                }else{
                    String err_code = root.elementText("err_code");
                    pay.setErr_code(err_code);
                    log.info("err_code:"+err_code);

                    String err_code_des = root.elementText("err_code_des");
                    pay.setErr_code_des(err_code_des);
                    log.info("err_code_des:"+err_code_des);
                }
            }else{
                String return_msg = root.elementText("return_msg");
                pay.setReturn_msg(return_msg);
                log.info("return_msg:"+return_msg);
            }
        }
        log.info("pay.toString():"+pay.toString());
        if("SUCCESS".equalsIgnoreCase(pay.getReturn_code()) && "SUCCESS".equalsIgnoreCase(pay.getResult_code())){
            //获取参数
            rewardRecordService.updateAfterPay(pay.getAttach(),pay.getOut_trade_no());
            buff.append("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[支付成功]]></return_msg></xml>");
        }else{
            buff.append("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>");
        }
        log.info("out :"+buff.toString());
        out.print(buff.toString());
    }



    //从输入流读取post参数
    protected String readStreamParameter(ServletInputStream in){
        StringBuilder buffer = new StringBuilder();
        BufferedReader reader=null;
        try{
            reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
            String line=null;
            while((line = reader.readLine())!=null){
                buffer.append(line);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(null!=reader){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer.toString();
    }
}
